package com.swotxu.oldwebproject.session.filter;

import com.swotxu.oldwebproject.redis.utils.RedisPropertiesUtil;
import com.swotxu.oldwebproject.session.conf.RedisSessionHelper;
import com.swotxu.oldwebproject.session.listener.filter.HttpServletWrapFilterListener;
import com.swotxu.oldwebproject.session.listener.filter.RedisFilterEvent;
import com.swotxu.oldwebproject.session.listener.filter.RedisSessionFilterListener;
import com.swotxu.oldwebproject.session.listener.filter.RefreshSessionAttrFilterListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * session过滤，extends OncePerRequestFilter 保证一次请求只过滤一次
 * 在过滤器中，用自己的 requset包装类包装原 request
 * 在 requset 包装类中，提供自己实现的 session 类。
 * 应用层使用 session 时： requset.getSession()， 拿到的 session 是面向redis操作的
 *
 * @Date: 2020/9/22 19:30
 * @Author: swotxu
 */
public class RedisSessionFilter extends OncePerRequestFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisSessionFilter.class);

    private static final String USE_REDIS_SESSION = "useRedisSession";

    private static Set<RedisSessionFilterListener> doFilterListener;
    private static Set<String> skipURISet;

    static {
        doFilterListener = new TreeSet<>(Comparator.comparingInt(RedisSessionFilterListener::fliterOrder));
        doFilterListener.add(new RefreshSessionAttrFilterListener());
        doFilterListener.add(new HttpServletWrapFilterListener());

        skipURISet = new HashSet<>();
        skipURISet.add("css");
        skipURISet.add("js");
        skipURISet.add("png");
        skipURISet.add("jpg");
        skipURISet.add("jpeg");
        skipURISet.add("gif");
    }

    protected void initFilterBean() {
        String initDisabled = getFilterConfig().getInitParameter(USE_REDIS_SESSION);
        LOGGER.info("useRedisSession: " + initDisabled);
        RedisSessionHelper.setUseRedisSession("Y".equalsIgnoreCase(initDisabled));
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (!RedisSessionHelper.isUseRedisSession() || !RedisPropertiesUtil.isEnable() || skipURI(request)) {
            filterChain.doFilter(request, response);
            return;
        }
        LOGGER.info("======= Use RedisSessionFilter ==========");
        RedisFilterEvent event = new RedisFilterEvent(request, response);
        doFilterBefore(event);
        filterChain.doFilter(event.getRequest(), event.getResponse());
        doFilterAfter(event);
    }

    private boolean skipURI(HttpServletRequest request) {
        String uri = request.getRequestURI();
        int index;
        return (index = uri.lastIndexOf(".")) != -1 && skipURISet.contains(uri.substring(index));
    }

    private void doFilterBefore(RedisFilterEvent event) {
        TreeSet<RedisSessionFilterListener> treeSet = (TreeSet) doFilterListener;
        for (Iterator<RedisSessionFilterListener> iterator = treeSet.iterator(); iterator.hasNext();) {
            iterator.next().doFilterBefore(event);
        }
    }

    private void doFilterAfter(RedisFilterEvent event) {
        TreeSet<RedisSessionFilterListener> treeSet = (TreeSet) doFilterListener;
        for (Iterator<RedisSessionFilterListener> iterator = treeSet.descendingIterator(); iterator.hasNext();) {
            iterator.next().doFilterAfter(event);
        }
    }
}
